#include "Logger.h"
#include <time.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <sys/stat.h>
#include <unistd.h>
#include <cstring>

const char* Logger::s_level[LEVEL_COUNT] = {
    "LEVEL_INIT",
    "DEBUG",
    "INFO ",
    "WARN ",
    "ERROR",
    "FATAL"
};

Logger::Logger()
{
    // 不在构造函数中创建目录，采用延迟创建策略
    // 启动日志写入线程
    m_writeThread = std::thread(&Logger::WriteLogThread, this);
}

Logger::~Logger()
{
    Stop();
}

void Logger::SetLogLevel(LogLevel level)
{
    if (level >= LEVEL_INIT && level < LEVEL_COUNT) {
        m_logLevel.store(level);
    }
}

void Logger::SetMaxFileSize(long int maxSize)
{
    if (maxSize > 0) {
        m_maxFileSize.store(maxSize);
    }
}

void Logger::SetLogPath(const std::string& path)
{
    std::lock_guard<std::mutex> lock(m_fileMutex);
    
    // 关闭当前文件（如果已打开）
    if (m_fileIsOpen.load() && m_filePtr) {
        fclose(m_filePtr);
        m_filePtr = nullptr;
        m_fileIsOpen.store(false);
    }
    
    // 设置新路径
    m_logPath = path;
    if (!m_logPath.empty() && m_logPath.back() != '/') {
        m_logPath += '/';
    }
    
    // 重置目录创建标志，下次写入时会重新创建目录
    m_directoryCreated.store(false);
    
    // 重置文件索引
    m_fileIndex.store(1);
}

Logger::LogLevel Logger::GetLogLevel() const
{
    return m_logLevel.load();
}

void Logger::Stop()
{
    if (!m_running.load()) {
        return;
    }
    
    m_running.store(false);
    
    // 通知停止条件变量
    {
        std::lock_guard<std::mutex> lock(m_stopMutex);
        m_stopCondition.notify_all();
    }
    
    // 等待写入线程结束
    if (m_writeThread.joinable()) {
        m_writeThread.join();
    }
    
    // 关闭文件
    std::lock_guard<std::mutex> lock(m_fileMutex);
    if (m_fileIsOpen.load() && m_filePtr) {
        fclose(m_filePtr);
        m_filePtr = nullptr;
        m_fileIsOpen.store(false);
    }
}

void Logger::WriteLogThread()
{
    while (m_running.load()) {
        try {
            // 获取日志消息（带超时）
            std::string msg;
            if (m_logQueue.PopWithTimeout(msg, 100)) { // 100ms 超时
                // 只有当有消息需要写入时，才检查并创建目录/文件
                CheckAndRotateLogFile();
                
                std::lock_guard<std::mutex> lock(m_fileMutex);
                if (m_fileIsOpen.load() && m_filePtr) {
                    fputs(msg.c_str(), m_filePtr);
                    fflush(m_filePtr);  // 强制写入磁盘
                }
            }
        } catch (const std::exception& e) {
            std::cerr << "Logger thread error: " << e.what() << std::endl;
        }
    }
    
    // 处理剩余的日志消息
    std::string msg;
    while (m_logQueue.TryPop(msg)) {
        // 确保目录和文件存在
        CheckAndRotateLogFile();
        
        std::lock_guard<std::mutex> lock(m_fileMutex);
        if (m_fileIsOpen.load() && m_filePtr) {
            fputs(msg.c_str(), m_filePtr);
            fflush(m_filePtr);
        }
    }
}

void Logger::CheckAndRotateLogFile()
{
    std::lock_guard<std::mutex> lock(m_fileMutex);
    
    // 延迟创建目录：只在第一次需要写入时才创建
    if (!m_directoryCreated.load()) {
        CreateDirectoryIfNotExists(m_logPath);
        m_directoryCreated.store(true);
    }
    
    std::string fileName = GetCurrentLogFileName();
    struct stat st;
    
    // 如果文件未打开，尝试打开
    if (!m_fileIsOpen.load()) {
        m_filePtr = fopen(fileName.c_str(), "a+");
        if (m_filePtr == nullptr) {
            std::cerr << "Failed to open log file: " << fileName << std::endl;
            return;
        }
        m_fileIsOpen.store(true);
        std::cout << "Log file opened: " << fileName << std::endl;
    }
    
    // 检查文件大小
    if (stat(fileName.c_str(), &st) == 0) {
        if (st.st_size >= m_maxFileSize.load()) {
            // 关闭当前文件
            if (m_filePtr) {
                fclose(m_filePtr);
                m_filePtr = nullptr;
                m_fileIsOpen.store(false);
            }
            
            std::cout << "Log file " << fileName << " size exceeded limit (" 
                      << st.st_size << " bytes), rotating to new file." << std::endl;
            
            // 增加文件索引
            m_fileIndex.fetch_add(1);
            
            // 打开新文件
            fileName = GetCurrentLogFileName();
            m_filePtr = fopen(fileName.c_str(), "a+");
            if (m_filePtr == nullptr) {
                std::cerr << "Failed to open new log file: " << fileName << std::endl;
                return;
            }
            m_fileIsOpen.store(true);
            std::cout << "New log file opened: " << fileName << std::endl;
        }
    } else {
        std::cerr << "Failed to get file status for: " << fileName << std::endl;
    }
}

std::string Logger::GetCurrentLogFileName() const
{
    return m_logPath + std::to_string(m_fileIndex.load()) + "-log.txt";
}

std::string Logger::FormatLogMessage(LogLevel level, const char* file, int line, const std::string& msg)
{
    // 获取当前时间
    time_t now = time(nullptr);
    tm* timeInfo = localtime(&now);
    
    char timestamp[64] = {0};
    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", timeInfo);
    
    // 提取文件名（去掉路径）
    const char* fileName = strrchr(file, '/');
    if (fileName) {
        fileName++; // 跳过 '/'
    } else {
        fileName = strrchr(file, '\\'); // Windows 路径
        if (fileName) {
            fileName++; // 跳过 '\'
        } else {
            fileName = file;
        }
    }
    
    // 格式化日志消息
    std::ostringstream oss;
    oss << "[" << timestamp << "] "
        << "[" << s_level[level] << "] "
        << "[" << fileName << ":" << line << "] "
        << msg << "\n";
    
    return oss.str();
}

// 创建目录的辅助函数（延迟创建）
void Logger::CreateDirectoryIfNotExists(const std::string& path)
{
    struct stat st;
    if (stat(path.c_str(), &st) != 0) {
        // 目录不存在，尝试创建
        std::string command = "mkdir -p " + path;
        int result = system(command.c_str());
        if (result != 0) {
            std::cerr << "Failed to create directory: " << path << std::endl;
        } else {
            std::cout << "Created log directory: " << path << std::endl;
        }
    } else if (!S_ISDIR(st.st_mode)) {
        std::cerr << "Path exists but is not a directory: " << path << std::endl;
    }
}